package com.auditlog.boot.aop.datasource;

import com.auditlog.datasource.DataSourceProxy;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.beans.BeansException;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Zhiyang.Zhang
 * @version 1.0
 * @date 2022/12/4 11:29
 */
@Slf4j
public class AuditLogDataSourceProxyCreator extends AbstractAutoProxyCreator {

    private final Set<String> excludes;

    private final Object[] advisors;

    public AuditLogDataSourceProxyCreator(String[] excludes) {
        this.excludes = new HashSet<>(Arrays.asList(excludes));
        this.advisors = buildAdvisors();
    }

    private Object[] buildAdvisors() {
        Advice advice = new AuditLogDataSourceInterceptor();
        return new Object[]{new DefaultIntroductionAdvisor(advice)};
    }

    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException {
        return this.advisors;
    }

    @Override
    protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        if (excludes.contains(beanClass.getName())) {
            return true;
        }
        return !DataSource.class.isAssignableFrom(beanClass);
    }

    @Override
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (!(bean instanceof DataSource)) {
            return bean;
        }

        if (!(bean instanceof DataSourceProxy)) {
            Object enhancer = super.wrapIfNecessary(bean, beanName, cacheKey);
            // 已经是个代理对象了
            if (bean == enhancer) {
                return bean;
            }
            DataSource origin = (DataSource) bean;
            DataSourceProxy proxy = new DataSourceProxy(origin);
            DataSourceProxyHolder.put(origin, proxy);
            return enhancer;
        }
        return bean;
    }
}
